/*
 * VideoService.java
 *
 * Copyright©2012 JMAS corporation. All rights reserved.
 */
package jp.co.jmas.jmasvideo.service;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;

import javax.jdo.JDOObjectNotFoundException;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.jdo.Transaction;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import jp.co.jmas.jmasvideo.dao.ErrorMessage;
import jp.co.jmas.jmasvideo.dao.PMF;
import jp.co.jmas.jmasvideo.dao.UserData;
import jp.co.jmas.jmasvideo.dao.Video;
import jp.co.jmas.jmasvideo.exception.ValidationException;

import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.apphosting.api.search.AclPb.AccessControlList;

@Path("/videos")
public class VideoService {
	@GET
	@Produces(MediaType.APPLICATION_JSON)
	public Response getVideos() {
		PersistenceManager pm = PMF.get().getPersistenceManager();

		Query query = pm.newQuery(Video.class);
		// TODO アクセス権のあるビデオのみに絞り込む！　query.setFilter();
		query.setOrdering("date desc");

		@SuppressWarnings("unchecked")
		List<Video> results = (List<Video>) query.execute();
		return Response.status(Response.Status.OK).entity(results).build();
	}

	@GET
	@Path("/{key}")
	@Produces(MediaType.APPLICATION_JSON)
	public Response getVideo(@PathParam("key") String key) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			// find entity with key
			Video video = pm.getObjectById(Video.class, key);
			return Response.status(Response.Status.OK).entity(video).build();

		} catch (JDOObjectNotFoundException e) {
			// No record exists
			return Response.status(Response.Status.NOT_FOUND).build();

		} finally {
			pm.close();
		}
	}

	@POST
	@Consumes(MediaType.APPLICATION_JSON)
	@Produces(MediaType.APPLICATION_JSON)
	public Response postVideo(Video video) throws ValidationException {
		String key = video.getKey();

		//		validate(video);

		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			// Make sure that the record does't exists
			try {
				@SuppressWarnings("unused")
				Video stored = pm.getObjectById(Video.class, key);
				ErrorMessage errorMessage = ErrorMessage.create("Already exists"); // TODO 存在
				return Response.status(Response.Status.BAD_REQUEST).entity(errorMessage).build();

			} catch (JDOObjectNotFoundException e) {
				// No record exists
			}

			// TODO ACLアクセス
			for (String fileName : new String[] { key + ".mp4", key + ".jpg" }) {
				// TODO GSFileOptionsを使えるのは新規作成時のみなので、自前でがんばる必要がある。
				AccessControlList acl = null; // TODO URLFetchで取得
				// TODO ACL更新
			}

			// 登録日・更新日のアップデート
			Date current = new Date();
			video.setRegistered(current);
			video.setLastUpdated(current);

			// Persist
			try {
				pm.makePersistent(video);

			} catch (Exception e) {
				// do nothing
				// TODO 例外がスローされるケースがあるか？
			}

			// メール送信
			try {

				// 送信先取得
				UserService us = UserServiceFactory.getUserService();
				if (!us.isUserLoggedIn()) {
					return Response.status(Response.Status.FORBIDDEN).build();
				}
				String mail = us.getCurrentUser().getEmail();
				String name = us.getCurrentUser().getNickname();

				Query query = pm.newQuery(UserData.class);
				query.setFilter("name == '" + mail + "'");

				@SuppressWarnings("unchecked")
				List<UserData> list = (List<UserData>) pm.newQuery(query).execute();

				if (list.isEmpty()) {
					return Response.status(Response.Status.FORBIDDEN).build();
				}

				List<String> dist = list.get(0).getDistribution();

				Properties props = new Properties();
				Session session = Session.getDefaultInstance(props, null);

				MimeMessage message = new MimeMessage(session);

				InternetAddress fromAddress = new InternetAddress(mail, name, "iso-2022-jp");
				message.setFrom(fromAddress);

				for (String address : dist) {
					InternetAddress toAddress = new InternetAddress(address, "", "iso-2022-jp");
					message.addRecipient(Message.RecipientType.TO, toAddress);
				}

				message.setSubject("動画が公開されました。", "ISO-2022-JP");
				message.setText("下記URLにて動画が公開されました。\n" +
						"http://jmasmatamura.appspot.com/video.jsp?id=" + key,
						"iso-2022-jp");

				Transport.send(message);

			} catch (UnsupportedEncodingException e) {
				// TODO 自動生成された catch ブロック
				e.printStackTrace();
			} catch (MessagingException e) {
				// TODO 自動生成された catch ブロック
				e.printStackTrace();
			}

			return Response.status(Response.Status.CREATED).entity(video).build();

		} finally {
			pm.close();
		}
	}

	@PUT
	@Path("{key}")
	@Consumes(MediaType.APPLICATION_JSON)
	@Produces(MediaType.APPLICATION_JSON)
	public Response putVideo(@PathParam("key") String key, Video video) {
		PersistenceManager manager = null;
		Transaction tx = null;

		try {
			manager = PMF.get().getPersistenceManager();
			tx = manager.currentTransaction();
			tx.begin();

			// find entity and update
			Video storedVideo = manager.getObjectById(Video.class, key);
			storedVideo.update(video);
			storedVideo.setLastUpdated(new Date());

			tx.commit();
			return Response.status(Response.Status.OK).entity(video).build();

		} catch (JDOObjectNotFoundException e) {
			// No record exists
			tx.rollback();
			return Response.status(Response.Status.NOT_FOUND).build();

		} catch (Throwable th) {
			// Other error thrown
			tx.rollback();
			ErrorMessage errorMessage = ErrorMessage.create(th.getMessage());
			return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errorMessage).build();

		} finally {
			manager.close();
		}
	}

	@DELETE
	@Path("{key}")
	@Consumes(MediaType.APPLICATION_JSON)
	@Produces(MediaType.APPLICATION_JSON)
	public Response deleteVideo(@PathParam("key") String key) {
		return Response.status(Response.Status.NO_CONTENT).build();
	}

	/**
	 * @param video
	 * @throws ValidationException
	 */
	private void validate(Video video) throws ValidationException {
		List<ErrorMessage> messageList = new ArrayList<ErrorMessage>();

		// Validate Key
		if (messageList.size() > 0) {
			throw new ValidationException(messageList);
		}
	}

}
